/*
 * JointSliderPanel.java -
 * Copyright (c) 2005 Carmine Lia
 * e-mail:      carmine.lia@libero.it
 * web-address: http://www.intermedia.sa.it/lia

 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
package javax.robotics.swing;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.robotics.engine.robots.Robot3D;
import javax.robotics.vecmath.RVector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import javolution.util.FastList;

/**
 * This class creates a panel of sliders to move the joints of Robot3D.
 * @author <a href="http://www.intermedia.sa.it/lia/">Carmine Lia</a>
 * @since 1.0.3
 * @version 15/10/2005
 */
public class JointSliderPanel extends JPanel implements ChangeListener
{
    private int dof = 0;
    private Robot3D robot;
    private RVector q0, qMin, qMax;
    private GridBagLayout gridbag;
    private GridBagConstraints c;
    private FastList<JSlider> slider;
    private JButton set, reset;
    /**
     * 
     */
    private static final long serialVersionUID = 3257288015520150835L;

    /**
     * Creates the panel of sliders.
     * @param robot the Robot3D to link to.
     */
    public JointSliderPanel(Robot3D robot)
    {
        super();

        this.robot = robot;
        dof = robot.getDof();
        q0 = robot.getQ();
        qMin = robot.getQMin();
        qMax = robot.getQMax();
        
        slider = new FastList<JSlider>(dof);

        gridbag = new GridBagLayout();
        c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        setLayout(gridbag);
 //       setBackground(Color.black);
        setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(BorderFactory
                .createLineBorder(Color.gray), "Joints Position"),BorderFactory.createEmptyBorder(5,5,5,5)));
 
        for (int i = 0; i < dof; i++)
        {
            JSlider s;
            if((robot.isJointPrismatic(i + 1) == Robot3D.PRISMATIC))
            {
                
                s = new JSlider(JSlider.HORIZONTAL, (int) Math.round(10*qMin.getElement(i)),(int) Math.round( 10*qMax.getElement(i)), 0);
                s.setMajorTickSpacing(2);
                s.setMinorTickSpacing(1);
                s.setPaintLabels(false);

            }
            else
            {
                final int min = (int) Math.round(Math.toDegrees(qMin.getElement(i)));
                final int max = (int) Math.round(Math.toDegrees(qMax.getElement(i)));
                final int range = max - min;
                s = new JSlider(JSlider.HORIZONTAL, min, max, 0);
                s.setMajorTickSpacing(range/4);
                s.setMinorTickSpacing(range/20);
                s.setPaintLabels(true);

            }
            s.setPaintTicks(true);
            s.setBorder(BorderFactory.createTitledBorder(BorderFactory
                    .createLineBorder(Color.gray),
                    new String("joint" + (i + 1)),
                    TitledBorder.DEFAULT_JUSTIFICATION,
                    TitledBorder.DEFAULT_POSITION, new Font("Helvetica",
                            Font.BOLD, 12), Color.black));
            c.gridy = i;
            gridbag.setConstraints(s, c);
            s.setName(Integer.toString(i + 1));
            if(robot.isJointImmobile(i+1) == false)
                s.addChangeListener(this);
            
            add(s);
            slider.add(s);
        }
        c.gridy = dof;
        add(createButtonPanel(), c);
        setValue(q0);
    }

    public void stateChanged(ChangeEvent e)
    {
        final JSlider source = (JSlider) e.getSource();
        final Integer joint = new Integer(source.getName());
       
        if(robot.isJointPrismatic(joint) == Robot3D.REVOLUTE)
         
            robot.setQ3D(Math.toRadians((double) source.getValue()), joint);
        else
            robot.setQ3D( ((double) source.getValue()) / 10.0, joint);
     }
    
    /**
     * Sets the value of sliders.
     * @param q the vector of new values.
     */
    public final void setValue(RVector q)
    {
        for (int i = 0; i < dof; i++)
        {
            final JSlider s = slider.get(i);
            if(robot.isJointPrismatic(i+1) == Robot3D.REVOLUTE)
                s.setValue((int) Math.round(Math.toDegrees(q.getElement(i))));
            else
                s.setValue((int) Math.round((q.getElement(i)))*10);
        }
    }
    
    /**
     * Gets the value of sliders.
     * @return the joints position.
     */
    public RVector getValue()
    {
        final RVector q = new RVector(dof);
        for (int i = 0; i < dof; i++)
        {
            final JSlider s = slider.get(i);
            if(robot.isJointPrismatic(i+1) == Robot3D.REVOLUTE)
                q.setElement(i, Math.toRadians(s.getValue()));
            else
                q.setElement(i,(double)s.getValue()/10.0);
        }
         return q;
    }
    /**
     * Updates the value of sliders to current robot position. 
     */
    public void updateValue()
    {
        setValue(robot.getQ());
    }
    
    /**
     * Resets the value of sliders to zero.
     */
    public void resetValue()
    {
        setValue(q0);
    }
    
    private JPanel createButtonPanel()
    {
        final JPanel bp = new JPanel();
        set = new JButton("Set");
        set.setToolTipText("Update the values to the current joints position");
        set.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                updateValue();
            }
        });
        bp.add(set);
        reset = new JButton("Reset");
        reset.setToolTipText("Sets the values to initial position");
        reset.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
               resetValue();
            }
        });
        bp.add(reset);
        return bp;
    }
    
}
